use reqwest::multipart;
use std::fs::File;
use std::io::Read;
use std::time::Duration;
use std::path::Path;
use log::{info, debug, error};

/// 百度网盘文件上传函数
///
/// # 参数说明
/// - `file_path`: 本地待上传文件路径
/// - `path`: 百度网盘目标路径（含文件名）
/// - `method`: 固定为 "upload"
/// - `access_token`: 百度网盘访问令牌
/// - `ondup`: 冲突处理策略（如 "overwrite" 表示覆盖）

// 创建百度网盘文件同步结构体
pub struct BaiduNetDisk {
    client: reqwest::Client,
    base_url: String,
    access_token: String,
}
impl BaiduNetDisk {
    /// 初始化百度网盘客户端
    pub fn new(base_url: &str, access_token: &str) -> Self {
        Self {
            client: reqwest::Client::builder()
                .timeout(Duration::from_secs(30)) // 设置超时时间为30秒
                .build().unwrap(),
            base_url: base_url.to_owned(),
            access_token: access_token.to_owned(),
        }
    }
    /// 上传文件到百度网盘
    pub async fn upload_file(&self, local_path: &str, remote_path: &str) -> Result<String, Box<dyn std::error::Error>> {
        // 校验文件路径并获取对象
        let mut file = Self::check_local_file(local_path)?;
        let mut file_content = Vec::new();
        // 读取文件内容
        file.read_to_end(&mut file_content);

        // 文件名消毒化
        let filename = Self::sanitize_filename(Path::new(local_path).file_name().unwrap().to_str().unwrap());
        // 验证远程路径格式
        Self::validate_remote_path(remote_path)?;
        // 构建完整的远程路径
        let full_remote_path = format!("{}{}", remote_path, filename);
        // 构建multipart表单数据
        let form = multipart::Form::new()
            .part("file", multipart::Part::bytes(file_content).file_name(filename));
        // 构建异步请求
        let response = self.client.post(&self.base_url)
           .query(&[("access_token", &self.access_token), ("path", &full_remote_path), ("method", &"upload".to_owned()), ("ondup", &"overwrite".to_owned())])
            .multipart(form)
           .send()
            .await?;
        // 处理响应
        if response.status().is_success() {
            let body = response.text().await?;
            info!("文件上传成功,百度网盘路径: '{}', 响应: '{}'", &full_remote_path, body);
            Ok(body)
        } else {
            error!("文件上传失败,百度网盘路径: '{}', 响应: '{}'", &full_remote_path, response.status());
            Err(format!("上传失败，状态码: {}", response.status()).into())

        }

    }

    // 检查本地文件是否存在
    fn check_local_file(local_path: &str) -> Result<File, Box<dyn std::error::Error>> {
        // 检查文件是否存在
        if !Path::new(local_path).exists() {
            return Err(Box::new(std::io::Error::new(std::io::ErrorKind::NotFound, "文件不存在")));
        }
        // 检查是否为文件
        if !Path::new(local_path).is_file() {
            return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, "不是一个文件")));
        }
        // 检查文件名是否为空
        if Path::new(local_path).file_name().unwrap().to_str().unwrap().is_empty() {
            return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, "文件名不能为空")));
        }
        // 打开文件
        let file = File::open(local_path).unwrap();
        Ok(file)
    }
    // 文件名消毒化
    fn sanitize_filename(filename: &str) -> String {

        filename
            .replace('\\', "_")
            .replace('?', "_")
            .replace('*', "_")
            .replace('>', "_")
            .replace('<', "_")
            .replace(':', "_")
            .replace('"', "_")
            .replace('|', "_")
            .trim() // 去除首尾空白
            .to_string()
    }
    // 验证远程路径格式
    fn validate_remote_path(path: &str) -> Result<(), Box<dyn std::error::Error>> {
        if !path.starts_with("/apps/") {
            return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, "路径必须以'/apps/'开头")));
        }
        // 其他格式校验
        if path.contains('\\') || path.contains('?') {
            return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, "路径中不能包含'\\'或'?'")));
        }
        Ok(())
    }
}